
package server;



import client.skills.SkillFactory;
import com.alibaba.druid.pool.DruidPooledConnection;
import database.DatabaseConnection;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import provider.MapleOverrideData;
import server.cashshop.CashItemFactory;
import server.console.Start;
import server.life.MapleLifeFactory;
import server.life.MapleMonsterInformationProvider;
import server.life.MobSkillFactory;
import server.maps.MapleMapFactory;
import server.quest.MapleQuest;
import server.shop.MapleShopFactory;
import server.skill.MapleForceAtomFactory;
import tools.Pair;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;



 public class InitializeServer
         {
    /*  42 */   private static final Logger log = LogManager.getLogger(InitializeServer.class.getName());








    public static boolean Initial() {
        /*  50 */
        initializeSetting();
        /*  51 */
        return initializeUpdateLog();

    }







    private static void initializeSetting() {
        /*  59 */
        try (DruidPooledConnection con = DatabaseConnection.getInstance().getConnection();
                /*  60 */         PreparedStatement ps = con.prepareStatement("UPDATE `accounts` SET `loggedin` = 0, `check` = 0")) {
            /*  61 */
            ps.executeUpdate();

        }
        /*  63 */ catch (SQLException ex) {
            /*  64 */
            throw new RuntimeException("[EXCEPTION] Please check if the SQL server is active.");

        }

    }








    private static boolean initializeUpdateLog() {
        /*  74 */
        if (!checkTableisExist()) {
            /*  75 */
            try (DruidPooledConnection con = DatabaseConnection.getInstance().getConnection();
                    /*  76 */           PreparedStatement ps = con.prepareStatement("CREATE TABLE `systemupdatelog` (`id`  INT(11) NOT NULL AUTO_INCREMENT,`patchid`  TINYINT(1) NOT NULL ,`lasttime`  TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP ,PRIMARY KEY (`id`))")) {
                /*  77 */
                ps.executeUpdate();

            }
            /*  79 */ catch (SQLException e) {
                /*  80 */
                e.printStackTrace();

            }

        }
        /*  83 */
        return checkTableisExist();

    }








    private static boolean checkTableisExist() {
        /*  92 */
        boolean exist = false;
        /*  93 */
        try (DruidPooledConnection con = DatabaseConnection.getInstance().getConnection();
                /*  94 */         PreparedStatement ps = con.prepareStatement("SHOW TABLES LIKE 'systemupdatelog'"); ResultSet rs = ps.executeQuery()) {
            /*  95 */
            if (rs.next()) {
                /*  96 */
                exist = true;

            }

        }
        /*  99 */ catch (SQLException e) {
            /* 100 */
            e.printStackTrace();

        }
        /* 102 */
        return exist;

    }









    private static boolean initializeMySQL() {
        /* 112 */
        for (UPDATE_PATCH patch : UPDATE_PATCH.values()) {
            /* 113 */
            if (!checkIsAppliedSQLPatch(patch.ordinal()) && (
                    /* 114 */         !applySQLPatch(patch.getSQL()) || !insertUpdateLog(patch.ordinal()))) {
                /* 115 */
                return false;

            }

        }

        /* 119 */
        return true;

    }









    private static boolean checkIsAppliedSQLPatch(int id) {
        /* 129 */
        try (DruidPooledConnection con = DatabaseConnection.getInstance().getConnection();
                /* 130 */         PreparedStatement ps = con.prepareStatement("SELECT id FROM systemupdatelog WHERE patchid = ?")) {
            /* 131 */
            ps.setInt(1, id);
            /* 132 */
            try (ResultSet rs = ps.executeQuery()) {
                /* 133 */
                if (rs.next()) {
                    /* 134 */
                    return true;

                }

            }

            /* 138 */
        } catch (SQLException e) {
            /* 139 */
            e.printStackTrace();

        }
        /* 141 */
        return false;

    }
    private static boolean insertUpdateLog(int patchid) {
        /* 151 */
        try (DruidPooledConnection con = DatabaseConnection.getInstance().getConnection();
                /* 152 */         PreparedStatement ps = con.prepareStatement("INSERT INTO systemupdatelog(id, patchid, lasttime) VALUES (DEFAULT, ?, CURRENT_TIMESTAMP)")) {
            /* 153 */
            ps.setInt(1, patchid);
            /* 154 */
            ps.executeUpdate();
            /* 155 */
            return true;

        }
        /* 157 */ catch (SQLException ex) {
            /* 158 */
            throw new RuntimeException(ex.getMessage());

        }

    }



    private static boolean applySQLPatch(String sql) {
        /* 163 */
        try (DruidPooledConnection con = DatabaseConnection.getInstance().getConnection();
                /* 164 */         PreparedStatement ps = con.prepareStatement(sql)) {
            /* 165 */
            ps.executeUpdate();
            /* 166 */
            return true;

        }
        /* 168 */ catch (SQLException e) {
            /* 169 */
            if (e.getMessage().contains("Duplicate column name")) {
                /* 170 */
                return true;

            }
            /* 172 */
            e.printStackTrace();
            /* 173 */
            return false;

        }

    }


    public static boolean initializeRedis(boolean reload, final Start.ProgressBarObservable observable) {

        try {
            final List<Runnable> runnables = new ArrayList<>();
            
            runnables.add(() -> {
                SkillFactory.loadDelays();
                MapleOverrideData.getInstance().init();
                SkillFactory.loadSkillData();
                SkillFactory.loadMemorySkills();
            });
            runnables.add(MapleItemInformationProvider.getInstance()::loadChatEmoticon);
            runnables.add(MapleItemInformationProvider.getInstance()::loadItemNameDesc);
            runnables.add(MapleItemInformationProvider.getInstance()::loadHairAndFace);
            runnables.add(MapleItemInformationProvider.getInstance()::loadFamiliarOption);
            runnables.add(() -> {
                MapleItemInformationProvider.getInstance().loadItemData();
                MapleMonsterInformationProvider.getInstance().load();
                MapleShopFactory.getInstance().loadShopData();
            });
            runnables.add(MapleItemInformationProvider.getInstance()::loadSetItemData);
            runnables.add(MapleItemInformationProvider.getInstance()::loadPotentialData);
            runnables.add(() -> MapleItemInformationProvider.getInstance().loadSocketData());
            runnables.add(MapleMapFactory::loadAllLinkNpc);
            runnables.add(MapleLifeFactory::loadMonsterName);
            runnables.add(MapleLifeFactory::loadMonsterID);
            runnables.add(MapleLifeFactory::loadQuestCounts);
            runnables.add(MapleMapFactory::loadAllMapName);
            runnables.add(MobSkillFactory::initialize);

            runnables.add(CashItemFactory.getInstance()::initialize);
            runnables.add(MapleQuest::initQuests);
            runnables.add(MapleForceAtomFactory.INSTANCE::initialize);
            final int currPro = observable.getProgress();
            final int singlePro = (100 - currPro) / (runnables.size() + 1);
            ForkJoinPool pool = new ForkJoinPool();
            pool.invoke(new RecursiveAction() {
                private AtomicInteger count = new AtomicInteger(1);

                protected void compute() {
                    List<RecursiveAction> task = runnables.parallelStream().map(runnable -> new RecursiveAction() {
                        protected void compute() {
                            runnable.run();
                            observable.setProgress(new Pair("[" + count + "/" + runnables.size() + "]", currPro + singlePro * count.get()));
                            count.incrementAndGet();
                        }
                    }).collect(Collectors.toList());
                    invokeAll(task);
                }
            });
            pool.shutdown();

            observable.setProgress(new Pair("服务端初始化完成，正在启动主界面...", Integer.valueOf(100)));
            /* 356 */
        } catch (Exception e) {
            /* 357 */
            log.error("服务端初始化失败", e);
            /* 358 */
            Start.showMessage("服务端初始化失败", "错误", 0);

            /* 360 */
            System.exit(0);

        }


        /* 364 */
        return true;

    }




       enum UPDATE_PATCH
             {
        /* 392 */     更新表格式_questinfo("ALTER TABLE `questinfo` ADD COLUMN `accountid`  int(11) NOT NULL DEFAULT 0 AFTER `questinfoid`"),
        /* 393 */     更新表格式_data_signin_reward("ALTER TABLE `data_signin_reward` CHANGE COLUMN `level` `iscash`  tinyint(1) NULL DEFAULT 0 AFTER `expiredate`"),
        /* 394 */     删除旧版签到记录表("DROP TABLE IF EXISTS `data_signin_log`");

             private final String sql;



             UPDATE_PATCH(String sql) {
            /* 400 */
            this.sql = sql;

        }



        public String getSQL() {
            /* 404 */
            return this.sql;

        }

    }

}
